#include <DHT.h>
#include <ArduinoJson.h>
#include <MQ135.h>

// 温湿度
#define DHTPIN 13          //连接到Arduino的数字输入引脚
#define DHTTYPE DHT11     //使用DHT11温湿度传感器
DHT dht(DHTPIN, DHTTYPE);

// 小灯泡
int ledPin[]   = {2,3,4,5};
int ledState[] = {0,0,0,0};

//风扇
int fanPin   = 6;                                                                                             
int fanState = 0;

//mq135
const int ANALOGPIN=0;
MQ135 gasSensor = MQ135(ANALOGPIN);

// 定时器中断触发的频率 (Hz)
const float interruptFrequency = 100; // 2 Hz
const unsigned long interval = 1000 / interruptFrequency; // 中断间隔时间 (ms)
int istimeout = 1;//是否计时结束,结束将更新数据至服务器

//初始化
void setup() {
  Serial.begin(9600);
   //初始化温湿度
  dht.begin();
  //初始化小灯泡
  for(int i=0;i<4;i++)
  {
    pinMode(ledPin[i],OUTPUT);
  }
  //初始化风扇
  pinMode(fanPin,OUTPUT);

  // 初始化定时器
  noInterrupts(); // 关闭中断
  // 设置定时器1
  TCCR1A = 0; // 设置 TCCR1A 寄存器为 0
  TCCR1B = 0; // 设置 TCCR1B 寄存器为 0
  // 将预分频器设置为 1024
  // TCCR1B |= (1 << CS12); // 设置 CS12 位为 1
  // TCCR1B |= (0 << CS11); // 设置 CS11 位为 0
  // TCCR1B |= (1 << CS10); // 设置 CS10 位为 1
  TCCR1B |= (1 << CS12); // 设置 CS12 位为 1
  TCCR1B |= (0 << CS11); // 设置 CS11 位为 0
  TCCR1B |= (0 << CS10); // 设置 CS10 位为 1

  // 计算并设置定时器的计数器值以实现所需的中断频率
  OCR1A = (int)(16000000 / (1024 * interruptFrequency)) - 1;
  TIMSK1 |= (1 << OCIE1A);  // 启用定时器中断
  interrupts(); // 启用中断
}

// 定时器中断服务程序
ISR(TIMER1_COMPA_vect) {
  static unsigned long previousMillis = 0; // 上次中断触发的时间
  unsigned long currentMillis = millis(); // 当前时间

  // 如果已经过了指定的间隔时间
  if (currentMillis - previousMillis >= interval) {
    istimeout = 1;
    previousMillis = currentMillis; // 更新上次中断触发的时间
  }
}

void loop() {  
  if (Serial.available()) 
  {
    readData_8266();
  }
  else if(istimeout)
  {
    String upData = "{\"DT\":0,\"Type\":1,\"Data\":[";
    upData += get_DHT11()+","; //读取温湿度传感器数据
    upData += get_LED(0)+","; //读取一号小灯泡的状况
    upData += get_LED(1)+","; //读取二号小灯泡的状况
    upData += get_LED(2)+","; //读取三号小灯泡的状况
    upData += get_LED(3)+","; //读取四号小灯泡的状况
    upData += get_Fan()+",";  //读取风扇的状况
    upData += get_MQ125();
    upData += "]}EOF";
    Serial.println(upData);  //读取led数据
    Serial.flush();
    istimeout = 0;
  }
}

// 读取从Ardunio UNO发送的串口数据
void readData_8266() 
{
  String content = "";    //清空数据缓存
  char character;  //读取到的数据

  while (Serial.available()) 
  {
    character = Serial.read();  //接收串口传输的数据
    content.concat(character);  //拼接字符串
    delay(2);
  }

  if (content != "") 
  {
    // 创建一个JSON缓冲区
    const size_t bufferSize = JSON_OBJECT_SIZE(2);
    DynamicJsonDocument doc(bufferSize);

    // 解析JSON数据
    DeserializationError error = deserializeJson(doc, content);

    // 检查解析是否成功
    if (error) {
      Serial.println(error.c_str());
      return;
    }
    
    int dt   = doc["DT"];
    int type = doc["Type"];

    if(dt==1 && type == 2) //当判断是控制命令时进行二次解析
    {
      // Serial.println(1);
      JsonArray array = doc["Data"].as<JsonArray>();
      for (JsonVariant value : array) {
        int id = value["id"];
        if(id<1006)
        {
            int ls = value["s"];
            set_LED(id-1002,ls);
        }
        else if(id == 1006)
        {
          int fs = value["s"];
          set_Fan(fs);
        }
      }
    }
  }
}

//获取温湿度传感器数据
String get_DHT11()
{
  float humidity = dht.readHumidity();     // 读取湿度数据
  float temperature = dht.readTemperature();   // 读取温度数据，单位为摄氏度

  // 将湿度和温度的数值转换为字符串
  String h = String(humidity, 2);  // 保留两位小数
  String t = String(temperature, 2);  // 保留两位小数

  return "{\"id\":1001,\"h\":" + h + ",\"t\":" + t + "}";
}

//获取空气传感器数据
String get_MQ125()
{
  String a = String(gasSensor.getPPM(),2);
  return "{\"id\":1007,\"a\":" + a + "}";
}

// 获取led数据
String get_LED(int led_count)
{
  return "{\"id\":"+(String)(1002+led_count)+",\"s\":"+(String)ledState[led_count]+"}";
}

// 设置led数据
void set_LED(int led_count,int led_state)
{
  if(led_count<4)
  {
    digitalWrite(ledPin[led_count],led_state);
    ledState[led_count] = led_state;
  }
}

//获取风扇状态
String get_Fan()
{
  return "{\"id\":1006,\"s\":"+(String)fanState+"}";
}

//设置风扇
void set_Fan(int state)
{
  Serial.println(state); 
  digitalWrite(fanPin,state);
  fanState = state;
}